/** 有顺序的Map,自制类
  重写了__item接口,可以用["key"]:=value当作map使用,
  重写了__Enum接口,for..in 循环可用

  By setycyas @2023-02-08
*/

class OrderMap {

  _array := []
  _map := Map()

  /* 构造函数,传入arr[]构造,如省却或长度不对则返回空的OrderMap
  */
  __New(arr := ""){
	  local k, v
	  if ((arr == "") or (Mod(arr.Length, 2) != 0)){
	    return this
      }
	  loop arr.Length/2 {
	    k := arr[2*A_Index-1]
      v := arr[2*A_Index]
      this[k] := v
	  }
  }

  /* 属性
  */
  ;重载[]接口
  __Item[key] {
    get {
      if (this._map.Has(key)){
        return this._map[key]
      } else {
        return
      }
    }
    set {
      if (!this._map.Has(key)){
        this._array.push(key)
      }
      this._map[key] := value
    }
  }

  /* 重载__Enum,该函数在for循环中被调用.
    for k, v in X语句的实际执行情况有两种可能:
    1. X是个枚举函数(文档里面叫Enumerator),该函数的参数是变量引用,循环变量被传入的X函数中
    并在执行过程对循环变量赋值,而函数的返回值是个布尔值,决定循环是否继续
    2. X是个对象,那么就会执行X.__Enum(num)函数,num是循环变量的个数,X.__Enum(num)返回一个枚举函数(Enumerator),
    不同的num可以返回不同的枚举函数.然后回到情况1

  */
  __Enum(num){
    local i := 1 ;枚举时使用的id,每次枚举+1,直到超过this._array长度

    ;f1,f2分别是for循环参数是1,2个时的枚举函数
    f1(&k) {
      if (i > this.Count){ ;循环中止
        return false
      } else { ;循环继续并对循环变量赋值
        k := this._array[i]
        i += 1
        return true
      }
    }
    f2(&k, &v) { ;过程同f1,只是赋值变量多了一个
      if (i > this.Count){
        return false
      } else {
        k := this._array[i], v := this._map[k]
        i += 1
        return true
      }
    }

    ;根据循环变量个数不同,返回不同的枚举函数
    if (num == 1) {
      return f1
    }
    if (num == 2) {
      return f2
    }
  }

  ;获取长度
  Count {
    get {
        return this._map.Count
    }
  }

  /* 公有函数
  */
  ;是否有key
  Has(key){
    return this._map.Has(key)
  }

  ;获取key表的一个克隆
  getKeys(){
    return this._array.Clone()
  }

  ;删除一个key,成功返回true,失败返回false
  remove(key){
    if (!this._map.Has(key)){
      return false
    }
    this._map.Delete(key)
    loop this._array.Length {
      if (this._array[A_Index] == key) {
        this._array.RemoveAt(A_Index)
        break
      }
    }
    return true
  }

}

/* 测试
*/
if (A_ScriptName == "OrderMap.2.ahk"){
  om := OrderMap(["a", 1, "b", 2, "c", 3, "e", 5, "f", 0])
  om["d"] := 4
  for k in om {
    MsgBox(k . " => " . om[k])
  }
  om.remove("c")
  for k, v in om {
    MsgBox(k . " => " . v)
  }
  MsgBox("count = " . om.Count)
}